#include <iostream>
using namespace std;
#include "circul_queue.hpp"
#include "mythread.hpp"
#include "task.hpp"
#include <unistd.h>

#define MAXNUM_PRO 5 // 生产线程的最大个数
#define MAXNUM_CUS 3 // 消费线程的最大个数

template <class T>
struct threadData
{
    circul_queue<T> *que; // 循环队列地址
    string threadName;    // 线程名
};

// 生产者任务函数
void *ProHandle(void *args)
{
    // 从args中获取线程名称和循环队列地址
    threadData<task> *data = static_cast<threadData<task> *>(args);
    string oper("+-*/%"); // 操作符列表
    while (true)
    {
        // 构建任务
        int x = rand() % 10;            // 左操作数
        int y = rand() % 10;            // 右操作数
        int pi = rand() % oper.size();  // 操作符索引
        char op = oper[pi];             // 操作符
        task newtask(x, y, op, mymath); // 任务
        // 派发任务
        data->que->push(newtask);
        cout << data->threadName << "生产了一个任务：" << newtask.whatTodo() << endl;
        sleep(2);
    }
    return nullptr;
}

// 消费者任务函数
void *CusHandle(void *args)
{
    // 从args中获取线程名称和循环队列地址
    threadData<task> *data = static_cast<threadData<task> *>(args);
    while (true)
    {
        // 接受任务
        task newtask = data->que->pop();
        cout << data->threadName << "消费了一个任务：" << newtask() << endl;
    }
    return nullptr;
}

int main()
{
    srand((unsigned int)time(nullptr)); // 随机数种子

    circul_queue<task> q; // 循环队列

    // 1、创建一批生产者线程和消费者线程
    vector<threadData<task> *> ProDatas; // 生产者线程信息列表
    vector<threadData<task> *> CusDatas; // 消费者线程信息列表

    vector<thread *> ProThreads; // 生产线程列表
    vector<thread *> CusThreads; // 消费线程列表

    // 创建生产者线程
    for (int i = 0; i < MAXNUM_PRO; i++)
    {
        // 格式化线程名
        char namebuffer[64] = {0};
        snprintf(namebuffer, sizeof(namebuffer), "ProdudterThread %d", i + 1);
        // 创建一个存储线程信息的结构,存储线程信息
        threadData<task> *newdata = new threadData<task>;
        newdata->que = &q;
        newdata->threadName = namebuffer;
        ProDatas.push_back(newdata);
        // 创建线程
        thread *newthread = new thread(ProHandle, (void *)newdata);
        ProThreads.push_back(newthread);
    }

    // 创建消费者线程
    for (int i = 0; i < MAXNUM_CUS; i++)
    {
        // 格式化线程名
        char namebuffer[64] = {0};
        snprintf(namebuffer, sizeof(namebuffer), "CustomerThread %d", i + 1);
        // 创建一个存储线程信息的结构,存储线程信息
        threadData<task> *newdata = new threadData<task>;
        newdata->que = &q;
        newdata->threadName = namebuffer;
        CusDatas.push_back(newdata);
        // 创建线程
        thread *newthread = new thread(CusHandle, (void *)newdata);
        CusThreads.push_back(newthread);
    }

    // 等待线程、然后销毁线程对象，再释放线程的相关信息
    for (int i = 0; i < MAXNUM_PRO; i++)
    {
        ProThreads[i]->join(); // 等待线程
        delete ProThreads[i];  // 释放线程对象
        delete ProDatas[i];    // 释放线程的相关信息
    }

    for (int i = 0; i < MAXNUM_CUS; i++)
    {
        CusThreads[i]->join(); // 等待线程
        delete CusThreads[i];  // 释放线程对象
        delete CusDatas[i];    // 释放线程的相关信息
    }

    return 0;
}